package demoMod.stsconsole.commands;

import demoMod.stsconsole.ConsoleEntry;
import demoMod.stsconsole.cards.AbstractCard;
import demoMod.stsconsole.core.AbstractCreature;
import demoMod.stsconsole.dungeons.AbstractDungeon;
import demoMod.stsconsole.enums.ErrType;
import demoMod.stsconsole.helpers.LocalizedStrings;
import demoMod.stsconsole.helpers.PromptHelper;
import demoMod.stsconsole.interfaces.SkimDrawPileSubscriber;
import demoMod.stsconsole.monsters.AbstractMonster;
import demoMod.stsconsole.potions.AbstractPotion;
import demoMod.stsconsole.powers.AbstractPower;
import demoMod.stsconsole.relics.AbstractRelic;
import demoMod.stsconsole.rewards.AbstractReward;
import demoMod.stsconsole.rooms.ShopRoom;

import java.util.*;
import java.util.Map;

public class Show extends AbstractCommand {
    @Override
    public void execute(String[] args, Scanner sc) {
        if (args.length == 0) {
            this.errMsg(ErrType.WRONG_ARGUMENT);
            return;
        }
        switch (args[0]) {
            case "deck":
                if (args.length == 1) {
                    for (int i = 0; i< AbstractDungeon.player.masterDeck.size(); i++) {
                        System.out.println(i + "\t" + AbstractDungeon.player.masterDeck.get(i).name);
                    }
                } else {
                    try {
                        int index = Integer.parseInt(args[1]);
                        if (index < 0 || index >= AbstractDungeon.player.masterDeck.size()) {
                            this.errMsg(ErrType.WRONG_ARGUMENT);
                            return;
                        }
                        AbstractCard card = AbstractDungeon.player.masterDeck.get(index);
                        card.calculateCardDamage(null);
                        System.out.println(card.name);
                        List<String> cmdStrings = LocalizedStrings.getCommandStrings("Smith");
                        System.out.print(cmdStrings.get(3));
                        if (card.cost == -1) {
                            System.out.println("X");
                        } else if (!card.canUse) {
                            System.out.println("-");
                        } else {
                            System.out.println(card.cost);
                        }
                        System.out.println(card.getUpdatedDescriptions(null));
                    } catch (NumberFormatException e) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                    }
                }
                break;
            case "hand":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                if (args.length == 1) {
                    for (int i=0;i<AbstractDungeon.player.hand.size();i++) {
                        System.out.println(i + "\t" + AbstractDungeon.player.hand.get(i).name);
                    }
                } else {
                    try {
                        int index = Integer.parseInt(args[1]);
                        if (index < 0 || index >= AbstractDungeon.player.hand.size()) {
                            this.errMsg(ErrType.WRONG_ARGUMENT);
                            return;
                        }
                        AbstractCard card = AbstractDungeon.player.hand.get(index);
                        card.calculateCardDamage(null);
                        System.out.println(card.name);
                        List<String> cmdStrings = LocalizedStrings.getCommandStrings("Smith");
                        System.out.println(cmdStrings.get(card.type.ordinal() + 7));
                        System.out.print(cmdStrings.get(3));
                        if (card.cost == -1) {
                            System.out.println("X");
                        } else if (!card.canUse) {
                            System.out.println("-");
                        } else {
                            System.out.println(card.cost);
                        }
                        System.out.println(card.getUpdatedDescriptions(null));
                    } catch (NumberFormatException e) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                    }
                }
                break;
            case "drawPile":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                List<String> cmdStrings = LocalizedStrings.getCommandStrings("Show");
                if (AbstractDungeon.player.drawPile.size() > 0) {
                    System.out.println(cmdStrings.get(1) + AbstractDungeon.player.drawPile.size());
                    List<AbstractCard> tmpList = new ArrayList<>(AbstractDungeon.player.drawPile);
                    Collections.shuffle(tmpList);
                    ConsoleEntry.triggerSubscribers(SkimDrawPileSubscriber.class, "onSkimDrawPile", new Class[]{List.class}, new Object[]{tmpList});
                    for (AbstractCard card : tmpList) {
                        System.out.println(card.name);
                    }
                } else {
                    AbstractDungeon.player.talk(cmdStrings.get(0));
                }
                break;
            case "discardPile":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                cmdStrings = LocalizedStrings.getCommandStrings("Show");
                if (AbstractDungeon.player.discardPile.size() > 0) {
                    System.out.println(cmdStrings.get(3) + AbstractDungeon.player.discardPile.size());
                    for (AbstractCard card : AbstractDungeon.player.discardPile) {
                        System.out.println(card.name);
                    }
                } else {
                    System.out.println(cmdStrings.get(2));
                }
                break;
            case "exhaustPile":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                cmdStrings = LocalizedStrings.getCommandStrings("Show");
                if (AbstractDungeon.player.exhaustPile.size() > 0) {
                    System.out.println(cmdStrings.get(4) + AbstractDungeon.player.exhaustPile.size());
                    for (AbstractCard card : AbstractDungeon.player.exhaustPile) {
                        System.out.println(card.name);
                    }
                }
                break;
            case "enemies":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                int i = 0;
                cmdStrings = LocalizedStrings.getCommandStrings("Show");
                for (AbstractCreature creature : AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters) {
                    if (!creature.isDeadOrEscaped()) {
                        if (creature instanceof AbstractMonster) {
                            System.out.println(i + "\t" + cmdStrings.get(5) + " " + creature.name);
                        } else {
                            System.out.println(i + "\t" + cmdStrings.get(6) + " " + creature.name);
                        }
                    }
                    i++;
                }
                break;
            case "health":
                if (args.length == 1) {
                    System.out.println(AbstractDungeon.player.getCurrentHealth() + "/" + AbstractDungeon.player.getMaxHealth());
                } else {
                    try {
                        int index = Integer.parseInt(args[1]);
                        if (index >= AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.size()) {
                            this.errMsg(ErrType.WRONG_ARGUMENT);
                            return;
                        }
                        AbstractCreature creature = AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.get(index);
                        System.out.println(creature.getCurrentHealth() + "/" + creature.getMaxHealth());
                    } catch (NumberFormatException e) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                    }
                }
                break;
            case "block":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                if (args.length == 1) {
                    System.out.println(AbstractDungeon.player.getCurrentBlock());
                } else {
                    try {
                        int index = Integer.parseInt(args[1]);
                        if (index >= AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.size()) {
                            this.errMsg(ErrType.WRONG_ARGUMENT);
                            return;
                        }
                        AbstractCreature creature = AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.get(index);
                        System.out.println(creature.getCurrentBlock());
                    } catch (NumberFormatException e) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                    }
                }
                break;
            case "powers":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                if (args.length == 1) {
                    for (AbstractPower power : AbstractDungeon.player.getPowers()) {
                        if (!power.isDone) {
                            System.out.println(power.name);
                            System.out.println(power.getUpdatedDescriptions());
                        }
                    }
                } else {
                    try {
                        int index = Integer.parseInt(args[1]);
                        if (index >= AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.size()) {
                            this.errMsg(ErrType.WRONG_ARGUMENT);
                            return;
                        }
                        AbstractCreature creature = AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.get(index);
                        for (AbstractPower power : creature.getPowers()) {
                            if (!power.isDone) {
                                System.out.println(power.name);
                                System.out.println(power.getUpdatedDescriptions());
                            }
                        }
                    } catch (NumberFormatException e) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                    }
                }
                break;
            case "intent":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                if (args.length != 2) {
                    this.errMsg(ErrType.WRONG_ARGUMENT);
                    return;
                }
                try {
                    int index = Integer.parseInt(args[1]);
                    if (index >= AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.size()) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                        return;
                    }
                    AbstractCreature creature = AbstractDungeon.currDungeon.currMapNode.room.monsters.monsters.get(index);
                    if (creature instanceof AbstractMonster) {
                        AbstractMonster monster = (AbstractMonster) creature;
                        monster.applyPowers();
                        AbstractMonster.MoveInfo moveInfo = monster.getCurrentMove();
                        printIntentStrings(monster, moveInfo);
                    }
                } catch (NumberFormatException e) {
                    this.errMsg(ErrType.WRONG_ARGUMENT);
                }
                break;
            case "energy":
                if (!PromptHelper.getPrompt().contains("Combat")) {
                    this.errMsg(ErrType.WRONG_PROMPT);
                    return;
                }
                System.out.println(AbstractDungeon.player.currEnergy + "/" + AbstractDungeon.player.numEnergyGainPerTurn);
                break;
            case "potions": {
                int index = 0;
                for (AbstractPotion potion : AbstractDungeon.player.getPotions()) {
                    System.out.println(index + "\t" + potion.name + "\t" + potion.getUpdatedDescription());
                    index++;
                }
                break;
            }
            case "relics": {
                int index = 0;
                for (AbstractRelic relic : AbstractDungeon.player.getRelics()) {
                    System.out.println(index + "\t" + relic.name);
                    index++;
                }
                break;
            }
            case "relic":
                if (args.length != 2) {
                    this.errMsg(ErrType.WRONG_ARGUMENT);
                    return;
                }
                try {
                    int index = Integer.parseInt(args[1]);
                    if (index < 0 || index >= AbstractDungeon.player.getRelics().size()) {
                        this.errMsg(ErrType.WRONG_ARGUMENT);
                        return;
                    }
                    AbstractRelic relic = AbstractDungeon.player.getRelics().get(index);
                    cmdStrings = LocalizedStrings.getCommandStrings("Show");
                    System.out.println(cmdStrings.get(24) + relic.name);
                    System.out.println(cmdStrings.get(25) + relic.getUpdatedDescriptions());
                    System.out.println(cmdStrings.get(27) + getRelicRarityString(relic.rarity));
                    System.out.println(cmdStrings.get(26) + relic.flavor);
                } catch (NumberFormatException e) {
                    this.errMsg(ErrType.WRONG_ARGUMENT);
                }
                break;
            case "rewards": {
                int index = 0;
                Map<Integer, AbstractReward> rewardMap = new HashMap<>();
                Map<AbstractReward, Integer> indexMap = new HashMap<>();
                for (AbstractReward reward : AbstractDungeon.currDungeon.currMapNode.room.rewards) {
                    System.out.print(index + "\t");
                    reward.preview();
                    rewardMap.put(index, reward);
                    indexMap.put(reward, index);
                    index++;
                }
                cmdStrings = LocalizedStrings.getCommandStrings("Show");
                for (i=0;i<index;i++) {
                    if (rewardMap.get(i).mutexReward != null && indexMap.get(rewardMap.get(i).mutexReward) != null) {
                        System.out.printf(cmdStrings.get(36) + "%n", i, indexMap.get(rewardMap.get(i).mutexReward));
                        rewardMap.remove(indexMap.get(rewardMap.get(i).mutexReward));
                        index--;
                    }
                }
                break;
            }
            case "gold":
                System.out.println(AbstractDungeon.player.getGold());
                break;
            case "shop": {
                if (!(AbstractDungeon.currDungeon.currMapNode.room instanceof ShopRoom)) {
                    this.errMsg(ErrType.COMMAND_NOT_AVAILABLE);
                    return;
                }
                cmdStrings = LocalizedStrings.getCommandStrings("Show");
                System.out.println(cmdStrings.get(37));
                ShopRoom.Shop shop = ShopRoom.currShop;
                System.out.println(cmdStrings.get(39)); //角色牌
                int index = 0;
                for (AbstractCard card : shop.coloredCards) {
                    if (card != null) {
                        System.out.println(index + "\t" + card.name + "\t" + cmdStrings.get(card.rarity.ordinal() + 27) + "\t" + card.getUpdatedDescriptions(null));
                        System.out.print(cmdStrings.get(38) + card.getPrice());
                        if (shop.coloredCards.indexOf(card) == shop.discountIndex) {
                            System.out.print(" " + cmdStrings.get(46));
                        }
                        System.out.println();
                    } else {
                        System.out.println(index + "\t" + cmdStrings.get(45));
                    }
                    index++;
                }
                System.out.println();
                System.out.println(cmdStrings.get(40)); //无色牌
                index = 0;
                for (AbstractCard card : shop.colorlessCards) {
                    if (card != null) {
                        System.out.println(index + "\t" + card.name + "\t" + cmdStrings.get(card.rarity.ordinal() + 27) + "\t" + card.getUpdatedDescriptions(null));
                        System.out.println(cmdStrings.get(38) + card.getPrice());
                    } else {
                        System.out.println(index + "\t" + cmdStrings.get(45));
                    }
                    index++;
                }
                System.out.println();
                System.out.println(cmdStrings.get(41)); //遗物
                index = 0;
                for (AbstractRelic relic : shop.relics) {
                    if (relic != null) {
                        System.out.println(index + "\t" + relic.name + "\t" + cmdStrings.get(relic.rarity.ordinal() + 27) + "\t" + relic.getUpdatedDescriptions());
                        System.out.println(cmdStrings.get(38) + relic.getPrice());
                    } else {
                        System.out.println(index + "\t" + cmdStrings.get(45));
                    }
                    index++;
                }
                System.out.println();
                System.out.println(cmdStrings.get(42)); //药水
                index = 0;
                for (AbstractPotion potion : shop.potions) {
                    if (potion != null) {
                        System.out.println(index + "\t" + potion.name + "\t" + potion.getUpdatedDescription());
                        System.out.println(cmdStrings.get(38) + potion.getPrice());
                    } else {
                        System.out.println(index + "\t" + cmdStrings.get(45));
                    }
                    index++;
                }
                System.out.println();
                System.out.print(cmdStrings.get(43)); //卡牌移除服务
                if (shop.cardPurgeService.canPurchase(shop.cardPurgeService, shop.cardPurgeService.getPrice())) {
                    System.out.println(cmdStrings.get(44) + "\t" + cmdStrings.get(38) + shop.cardPurgeService.getPrice());
                } else {
                    System.out.println(cmdStrings.get(45));
                }
                break;
            }
            default:
                this.errMsg(ErrType.WRONG_ARGUMENT);
        }
    }

    public static String getRelicRarityString(AbstractRelic.RelicRarity rarity) {
        List<String> cmdStrings = LocalizedStrings.getCommandStrings("Show");
        switch (rarity) {
            case COMMON:
                return cmdStrings.get(28);
            case UNCOMMON:
                return cmdStrings.get(29);
            case RARE:
                return cmdStrings.get(30);
            case BOSS:
                return cmdStrings.get(31);
            case SHOP:
                return cmdStrings.get(32);
            case SPECIAL:
                return cmdStrings.get(33);
            case STARTER:
                return cmdStrings.get(34);
            default:
                return cmdStrings.get(35);
        }
    }

    private void printIntentStrings(AbstractMonster monster, AbstractMonster.MoveInfo info) {
        List<String> cmdStrings = LocalizedStrings.getCommandStrings("Show");
        switch (info.intent) {
            case ATTACK:
                System.out.printf(cmdStrings.get(7), (int) info.info.output);
                if (info.isMultiDamage) {
                    System.out.printf(cmdStrings.get(22) + "%n", info.multi);
                } else {
                    System.out.println(cmdStrings.get(23));
                }
                break;
            case DEFEND:
                System.out.println(cmdStrings.get(8));
                break;
            case ATTACK_DEFEND:
                System.out.printf(cmdStrings.get(9), (int) info.info.output);
                if (info.isMultiDamage) {
                    System.out.printf(cmdStrings.get(22) + "%n", info.multi);
                } else {
                    System.out.println(cmdStrings.get(23));
                }
                break;
            case DEBUFF:
                System.out.printf(cmdStrings.get(10) + "%n", monster.defaultTarget.name);
                break;
            case ATTACK_DEBUFF:
                System.out.printf(cmdStrings.get(11) + "%n", monster.defaultTarget.name, (int) info.info.output);
                if (info.isMultiDamage) {
                    System.out.printf(cmdStrings.get(22) + "%n", info.multi);
                } else {
                    System.out.println(cmdStrings.get(23));
                }
                break;
            case DEFEND_DEBUFF:
                System.out.printf(cmdStrings.get(12) + "%n", monster.defaultTarget.name);
                break;
            case BUFF:
                System.out.println(cmdStrings.get(13));
                break;
            case ATTACK_BUFF:
                String s = " " + String.format(cmdStrings.get(22), info.multi);
                if (info.isMultiDamage) {
                    System.out.printf(cmdStrings.get(14) + "%n", (int) info.info.output, s);
                } else {
                    System.out.printf(cmdStrings.get(14) + "%n", (int) info.info.output, "");
                }
                break;
            case DEFEND_BUFF:
                System.out.println(cmdStrings.get(15));
                break;
            case BUFF_DEBUFF:
                System.out.printf(cmdStrings.get(16) + "%n", monster.defaultTarget.name);
                break;
            case STRONG_DEBUFF:
                System.out.printf(cmdStrings.get(17) + "%n", monster.defaultTarget.name);
                break;
            case UNKNOWN:
            default:
                System.out.println(cmdStrings.get(18));
                break;
            case STUNNED:
                System.out.println(cmdStrings.get(19));
                break;
            case SLEEPING:
                System.out.println(cmdStrings.get(20));
                break;
            case ESCAPE:
                System.out.println(cmdStrings.get(21));
                break;
        }
    }

    @Override
    public boolean requiredPrompt(String currentPrompt) {
        return currentPrompt.contains("Dungeon");
    }
}
